package co.yixiang.modules.quartz.utils;

import co.yixiang.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * 执行定时任务
 * 该类实现了Callable接口，用于封装一个可被定时执行的任务
 * 它通过反射调用目标对象的目标方法，支持带有字符串参数的方法和无参数的方法
 * @author /
 */
@Slf4j
public class QuartzRunnable implements Callable {

    // 目标对象，即要执行方法的bean实例
	private Object target;
	// 目标方法，即定时任务要执行的方法
	private Method method;
	// 方法的参数，如果有的话
	private String params;

    /**
     * 构造函数，用于初始化QuartzRunnable实例
     * 根据beanName从Spring上下文中获取bean实例，并根据methodName和params初始化method
     *
     * @param beanName bean的名称，用于从Spring上下文中获取bean实例
     * @param methodName 方法的名称，用于反射调用
     * @param params 方法的参数，如果方法需要参数的话
     * @throws NoSuchMethodException 如果找不到指定的方法
     * @throws SecurityException 如果访问方法出现问题
     */
	QuartzRunnable(String beanName, String methodName, String params)
			throws NoSuchMethodException, SecurityException {
		// 获取目标对象
		this.target = SpringContextHolder.getBean(beanName);
		this.params = params;

		// 根据params是否存在来决定是获取带参数的方法还是不带参数的方法
		if (StringUtils.isNotBlank(params)) {
			// 如果params非空，获取带有一个String类型参数的方法
			this.method = target.getClass().getDeclaredMethod(methodName, String.class);
		} else {
			// 如果params为空，获取不带参数的方法
			this.method = target.getClass().getDeclaredMethod(methodName);
		}
	}

    /**
     * 实现Callable接口的call方法，用于执行定时任务
     * 它通过反射调用目标方法，并处理可能的异常
     *
     * @return null，因为这个实现中不关心返回值
     * @throws Exception 如果方法调用出现问题
     */
	@Override
	public Object call() throws Exception {
		// 确保方法可以被访问，即使是私有方法
		ReflectionUtils.makeAccessible(method);
		if (StringUtils.isNotBlank(params)) {
			// 如果params非空，调用带有参数的方法
			method.invoke(target, params);
		} else {
			// 如果params为空，调用不带参数的方法
			method.invoke(target);
		}
		return null;
	}
}
